

var keystack = [];
var is_digraph = 0;

var divimage;
var imgpage;
var divcontrolbar;
var divfratext;
var tatext;
var divctlnav;
var divpreview; 
var divctlimg;
var divctlwc;
var divstatusbar;

var formedit;
var formcontext;

// object of span ids - wc_word_line;
var _span_ids = {};

var is_wordchecking = false;
// var is_sync = false;
var _active_scroll_id = null;
var _sync_x, _sync_y;
var is_tail_space;

var ajax;
var ajaxActionFunc;
var charpicker;
var selectors;
var pickers;
var _contexts;
var _date = new Date();
var _active_ctl;
var _active_charselector;
var _active_char;
var _active_context_index;
var _range;
var _wc_wakeup = 0;
var _wc_token = 0;
var _wc_response;

var barpos;

function $(id) {
    return document.getElementById(id);
}

function pf$(id) {
    return frames.proofframe.document.getElementById(id);
}

function ctl$(id) {
    return frames.ctlsframe.document.getElementById(id);
}

function addEvent(obj, evType, fn) {
    if(obj.addEventListener) {
        obj.addEventListener(evType, fn, false);
        return true;
    }
    else if(obj.attachEvent) {
        var r = obj.attachEvent("on" + evType, fn);
        return r;
    }
}

function eBodyLoad() {
    formedit        = pf$("formedit");
    pfbody          = pf$("pfbody");
    divimage        = pf$("divimage");
    divfratext      = pf$("divfratext");
    divcontrolbar   = pf$("divcontrolbar");
    tatext          = pf$("tatext");
    imgpage         = pf$("imgpage");
                   
    divpreview      = pf$("divpreview");
    divctlimg       = pf$("divctlimg");
    divctlnav       = pf$("divctlnav");
    divctlwc        = pf$("divctlwc");
    divstatusbar    = pf$("divstatusbar");
                    
    applylayout(null);

    // addEvent(window,        "resize",         eResize);
    addEvent(tatext,              "focus",    eTextFocus);
    addEvent(tatext,              "blur",     eTextBlur);
    addEvent(divimage,            "focus",    eImgFocus);
    addEvent(divimage,            "blur",     eImgBlur);
    addEvent(divimage,            "click",    eImgClick);
    // addEvent(tatext,               "select",  eTextSelect);
    // addEvent(tatext,               "keyup",   eKeyUp);
    // tatext.onkeydown = eKeyDown;
    // tatext.onkeypress = eKeyPress;
    addEvent(proofframe.document, "keydown",  eKeyDown);
    addEvent(proofframe.document, "keypress", eKeyPress);
    addEvent(tatext,              "click",    eTextClick);
    // addEvent(tatext,                 "focus",    eTextFocus);
    addEvent(tatext,              "change",   eTextChange);
    // addEvent(tatext,                 "load",     eTextLoad);
    // addEvent(tatext,                 "reset",    eTextReset);
    addEvent(divfratext,          "scroll",   eScroll);
    addEvent(divimage,            "scroll",   eScroll);
    // addEvent(tatext,                 "scroll",   eTextScroll);

    // scroll img controls to zoom
    if(divctlimg.onmousewheel) {
        addEvent(divctlimg,       "mousewheel", eImgCtlWheel);
    } else {
        divctlimg.addEventListener("DOMMouseScroll", 
                                    eImgCtlWheel, false);
    }
    addEvent(proofframe.document, "mousemove", eMouseMove);
    addEvent(pf$('linksync'),     "click",     eToggleSync);
    addEvent(pf$('linkzoomin'),   "click",     eZoomIn);
    addEvent(pf$('linkzoomout'),  "click",     eZoomOut);
    addEvent(pf$('linklayout'),   "click",     eLinkLayout);
    addEvent(pf$('linksearch'),   "click",     eLinkSearch);
    addEvent(pf$('linkwc'),       "click",     eWordCheck);
    addEvent(pf$('returnpage'),   "click",     eReturnPage);
    addEvent(pf$('savetemp'),     "click",     eSaveTemp);
    addEvent(pf$('savequit'),     "click",     eSaveQuit);
    addEvent(pf$('savenext'),     "click",     eSaveNext);
    addEvent(pf$('quit'),         "click",     eQuit);
    addEvent(pf$('linkupload'),   "click",     eShowUpload);
    addEvent(pf$('btntxtleft'),   "click",     eTextLeft);
    addEvent(pf$('btntxtright'),  "click",     eTextRight);
    addEvent(pf$('selfontface'),  "change",    eSetFontFace);
    addEvent(pf$('selfontsize'),  "change",    eSetFontSize);
}

function px(val) {
    return val ? val.toString() + "px" : "";
}

function applylayout(rsp) {
    var layout = formedit.layout.value;
    var barpct = (rsp == null) 
            ? formedit.barpct.value
            : rsp.imgpct;
    barpos = (layout == "horizontal")
            ? pfbody.clientHeight * barpct / 100 - 28
            : pfbody.clientWidth * barpct / 100;

    if(rsp != null) {
        imgpage.style.width         = rsp.zoom + "%";
        SetFontSizeSelector(rsp.fontsize);
        SetFontFaceSelector(rsp.fontface);
        divpreview.style.fontFamily =
        tatext.style.fontFamily     = rsp.fontface;
        divpreview.style.fontSize   =
        tatext.style.fontSize       = rsp.fontsize;
    }
    else {
        imgpage.style.width         = formedit.zoom.value + "%";
        divpreview.style.fontFamily =
        tatext.style.fontFamily     = pf$('selfontface').value
        divpreview.style.fontSize   =
        tatext.style.fontSize       = pf$('selfontsize').value
    }

    if(layout == 'horizontal') {
        divimage.style.height = px(barpos);
        divimage.style.width  = px(pfbody.clientWidth);
        divimage.style.visibility   = "visible";

        divcontrolbar.style.top = px(barpos);
        divcontrolbar.style.left = 0;
        divcontrolbar.style.width = px(pfbody.clientWidth);
        divcontrolbar.style.visibility = "visible";

        divfratext.style.top = px(divcontrolbar.offsetTop 
                        + divcontrolbar.offsetHeight);
        divfratext.style.left = 0;
        divfratext.style.height = px(divstatusbar.offsetTop
            - divfratext.offsetTop);
        divfratext.style.width = px(pfbody.clientWidth);
        divfratext.style.visibility = "visible";
    }
    else {
        divimage.style.height     = px(divstatusbar.offsetTop);
        divimage.style.width      = px(barpos);
        divimage.style.visibility = "visible";
                                  
        divcontrolbar.style.top   = 0;
        divcontrolbar.style.left  = px(barpos);
        divcontrolbar.style.width = px(pfbody.clientWidth - barpos+1);
        divcontrolbar.style.visibility = "visible";

        divfratext.style.top      = px(divcontrolbar.offsetHeight+1);
        divfratext.style.left     = px(barpos);
        divfratext.style.width    = px(pfbody.clientWidth - barpos);
        divfratext.style.height   = px(pfbody.clientHeight
                            - divcontrolbar.offsetHeight 
                            - divstatusbar.offsetHeight);
        divfratext.style.visibility = "visible";
    }
    set_text_size();
}

function set_text_size() {
    tatext.style.height    = px(divpreview.scrollHeight);
    tatext.style.width     = px(divpreview.scrollWidth);
}

function eCtlInit() {
    // if(ctlframe) {
        charpicker = ctl$('charpicker');
        selectors  = ctl$('selectors');
        pickers    = ctl$('pickers');
    // }
    if(charpicker) {
        selectors.innerHTML = char_selectors(' ');
        pickers.innerHTML   = char_pickers(' ');

        // addEvent(charpicker, "click", eCharClick);
    }

}

// pickers

function char_selector_row(str) {
    var i;
    var s = '<tr>\n';
    var a = str.split(/ /g);
    var alen = a.length;
    for (i = 0; i < alen; i++) {
        s += ('<td class="selector">' + a[i] + '</td>\n');
    }
    s += '</tr>\n';
    return s;
}

function char_row(str) {
    var i;
    var s = '<tr>\n';
    var imax = str.length;
    for (i = 0; i < imax; i++) {
        s += ('<td class="picker">' + str[i] + '</td>\n');
    }
    s += '</tr>\n';
    return s;
}

function c_row(selkey)
{
    var sel = c_select[selkey];
    var charstr = sel.chars;
    var i;
    var s = '<tr>\n';
    var imax = charstr.length;
    for (i = 0; i < imax; i++) {
        s += ('<td class="picker"');
        if(sel.prompt) {
            s += (' title="' + sel.prompt + '"');
        }
        s += ('>' + sel.chars + '</td>\n');
    }
    s += '</tr>\n';
    return s;
}

/*
var c_select = {
    "A": {   
        "chars": "ÀàÁáÂâÄäÅåÃãÆæĀāĂăĄą"
    },
    "E": {
        "chars": "ÈèÉéÊêËëĖėĘęĚěĔĕĒē"
    },
    "I": {
        "chars": "ÌìÍíÎîÏïĨĩĪīĬĭǏǐĮį"
    },
    "O": {
        "chars": "ÒòÓóÔôÖöÕõØøŌōŎŏǑǒŒœ"
    },
    "U": {
        "chars": "ÙùÚúÛûÜüŨũŪūŭŬŭ"
    },
    "Y": {
        "chars": "Ýý&#255;"
    },

    "+": {
        "prompt": "punctuation",
        "chars": ["$¢£‰¤¥¡¿©®«»„“ÐðÞþßǶƕÑñĝĥĵ†‡•⁂",
                  "′″‴¦§¨ª¬¯°±²³´¶·¸¹º¼½¾×÷™ȣƺ"]
    },

    "CD": {
        "prompt": "C D",
        "chars": "ÇçĆćĈĉĊċČčƆƇÐðĎďĐđƉƊ"
    },

    "LN": {
        "prompt": "L M N",
        "chars": "ĹĺĻļĽľĿŀŁłÑñŃńŅņŇňŉŊŋ"
    },

    "RS": {
        "prompt": "R S",
        "chars": "ŔŕŖŗŘřßŚśŜŝŞşŠšſ"
    },

    "TZ": {
        "prompt": "T Z",
        "chars": "ŢţŤťŦŧŹźŻżŽž",
        "cprompts": {
            "Ţ": "T-dot",
            "Ż": "dot-Z"
        }
    },

    "αβγ": {
        "prompt": "Greek basic",
        "chars": "αβγδεζηθϝικλμνξοπρσςτυφχψω ·;",
        "cprompts": {
            "α": "alpha",
            "β": "beta",
            "γ": "gamma",
            "δ": "delta"
        }
    },

    "ἄἒ": {
        "prompt":"",
        "chars": ["αβγδεζηθϝικλμνξοπρσςτυφχψω ·;",
                  "ΑΒΓΔΕΖΗΘϜΙΚΛΜΝΞΟΠΡΣ ΤΥΦΧΨΩ ʹ͵"]
    },

    "ἠΐ": {
        "prompt":"",
        "chars": ["ἠήἡἢἣἤἥἦἧᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄ ίΐϊἰἱἲἳἴἵἶἷὶίῐῑῒΐ",
                  "ἠήἡἢἣἤἥἦἧᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄ ίΐϊἰἱἲἳἴἵἶἷὶίῐῑῒΐ"]
    },

    "όύ": {
        "prompt":"",
        "chars": ["όὀὁὂὃὄὅὸό ύϋ ὐὑὒὓὔὕὖὗ ὺύῠῡ",
                  "ΌὈὉὊὋὌὍῸΌ ΎΫ  Ὑ Ὓ Ὕ Ὗ ῪΎῨῩ"]
    },

    "ώῤ": {
        "prompt":"",
        "chars": ["ώὠὑὢὣὤὥὦὧ ὼώ ᾠᾡᾢᾣᾤᾥᾦᾧ ῲῳῴῶῷϟϡῤῥ",
                  "ΏὨὙὪὫὬὭὮὯ ῺΏ ᾨᾩᾪᾫᾬᾭᾮᾯ  ῼ   ϞϠ Ῥ"]
    },

    "Ћћ": {
        "prompt":"Cyrillic",
        "chars": ["ЂђЃѓЀѐЁёЄєЅѕЍѝІіЇїЙйЈјЉљ",
                  "ЊњЋћЌќЎўЏџЩщЪъЫыЬьЭэЮюЯя"]
    },

    "Ѡѡ": {
        "prompt":"Cyrillic",
        "chars": ["ѢѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱ", 
                  "ѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂Ğğ"]
    }

    // "key": {
        // "prompt":"",
        // "chars": ["",
                  // ""]
    // }
};
*/

function char_selectors() {
    var s = "<table class='tblpicker'>\n";
    s += char_selector_row("A E I O U + Y CD LN RS TZ αβγ ἄἒ ἠΐ όύ ώῤ Ћћ Ѡѡ");
    s += "\n</table>\n";
    return s;
}

function char_pickers(cgroup) {
    // var s = "<table class='tblpicker'>\n";
    // s += char_selector_row("A E I O U + Y CD LN RS TZ αβγ ἄἒ ἠΐ όύ ώῤ Ћћ Ѡѡ");

    // s += "</table><table class='tblpicker'>\n";
    var s = "<table class='tblpicker'>\n";

    switch (cgroup) {
    case 'A':
        s += char_row('ÀàÁáÂâÄäÅåÃãÆæĀāĂăĄą');

        break;
    case 'E':
        s += char_row('ÈèÉéÊêËëĖėĘęĚěĔĕĒē');
        break;

    case 'I':
        s += char_row('ÌìÍíÎîÏïĨĩĪīĬĭǏǐĮį');
        break;
    case 'O':
        s += char_row('ÒòÓóÔôÖöÕõØøŌōŎŏǑǒŒœ');

        break;
    case 'U':
        s += char_row('ÙùÚúÛûÜüŨũŪūŭŬŭ');
        break;
    case '+':
        s += char_row('$¢£‰¤¥¡¿©®«»„“ÐðÞþßǶƕÑñĝĥĵ†‡•⁂');
        s += char_row('′″‴¦§¨ª¬¯°±²³´¶·¸¹º¼½¾×÷™ȣƺ');
        break;
    case 'Y':
        s += char_row('Ýý&#255;');
        break;
    case 'CD':
        s += char_row('ÇçĆćĈĉĊċČčƆƇÐðĎďĐđƉƊ');
        break;
    case 'LN':
        s += char_row('ĹĺĻļĽľĿŀŁłÑñŃńŅņŇňŉŊŋ');
        break;

    case 'RS':
        s += char_row('ŔŕŖŗŘřßŚśŜŝŞşŠšſ');
        break;

    case 'TZ':
        s += char_row('ŢţŤťŦŧŹźŻżŽž');
        break;

    case 'αβγ':
        s += char_row('αβγδεζηθϝικλμνξοπρσςτυφχψω ·;');
        s += char_row('ΑΒΓΔΕΖΗΘϜΙΚΛΜΝΞΟΠΡΣ ΤΥΦΧΨΩ ʹ͵');
        break;

    case 'ἄἒ':
        s += char_row('άὰἂἄἆἁἃἅἇᾀᾁᾂᾃᾄᾅᾆᾇᾰᾱᾲᾳᾴᾶᾷ έὲἐἑἒἓἔἕἒέ');
        s += char_row('ΆᾺἊἌἎἉἋἍἏᾈᾉᾊᾋᾌᾍᾎᾏᾸᾹ ᾼ    ΈῈἘἙἚἛἜἝἚΈ');
        break;

    case 'ἠΐ':
        s += char_row('ἠήἡἢἣἤἥἦἧᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄ ίΐϊἰἱἲἳἴἵἶἷὶίῐῑῒΐ');
        s += char_row('ἨΉἩἪἫἬἭἮἯᾘᾙᾚᾛᾜᾝᾞᾟ ῌ  ΊΐΪἸἹἺἻἼἽἾἿῚΊῘῙ  ');
        break;

    case 'όύ':
        s += char_row('όὸὀὁὂὃὄὅό ύϋ ὐὑὒὓὔὕὖὗ ὺύῠῡ');
        s += char_row('ΌῸὈὉὊὋὌὍΌ ΎΫ  Ὑ Ὓ Ὕ Ὗ ῪΎῨῩ');
        break;

    case 'ώῤ':
        s += char_row('ώὠὑὢὣὤὥὦὧ ὼώ ᾠᾡᾢᾣᾤᾥᾦᾧ ῲῳῴῶῷϟϡῤῥ'); 
        s += char_row('ΏὨὙὪὫὬὭὮὯ ῺΏ ᾨᾩᾪᾫᾬᾭᾮᾯ  ῼ   ϞϠ Ῥ'); 
        break;

    case 'Ћћ':
        s += char_row('ЂђЃѓЀѐЁёЄєЅѕЍѝІіЇїЙйЈјЉљ');
        s += char_row('ЊњЋћЌќЎўЏџЩщЪъЫыЬьЭэЮюЯя');
        break;
    case 'Ѡѡ':
        s += char_row('ѢѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱ');
        s += char_row('ѲѳѴѵѶѷѸѹѺѻѼѽѾѿҀҁ҂Ğğ');
        break;

    default:
        break;
    }


    s += '</table>\n';
    return s;
}

function InsertChar(c) {
    var sel = SelectedText();
    ReplaceText(c);
    set_text_size();
    if(is_wordchecking) {
        awcWordcheck();
    }
    return false;
}


function eCharClick(e) {
    var c;
    var t;
    if(!e) { e = window.event; }
    t = e.originalTarget ? e.originalTarget : e.srcElement;
    c = t.value ? t.value : t.innerHTML;
    if(t.className == "selector") {
        if(_active_charselector) {
            _active_charselector.style.border = "0";
        }
        _active_charselector = t;
        _active_charselector.style.border = "2px solid red";
        // charpicker.innerHTML = char_pickers(c);
        pickers.innerHTML = char_pickers(c);
        return true;
    }

    if(t.className == "picker") {
        if(_active_char) {
            _active_char.style.border = "0";
        }
        _active_char = t;
        t.style.border = "2px solid red";
        InsertChar(c);
    }
    return true;
}

function ePickerOut(e) {
    if(!e) { e = window.event; }
    ctl$('charshow').style.display = "none";
}

function ePickerOver(e) {
    var tgt;
    if(!e) { e = window.event; }

    tgt = e.target ? e.target : e.srcElement;
    if(tgt.nodeName.toLowerCase() !== "td") {
        return;
    }
    if(tgt.className != 'picker') {
        return;
    }
    if(! tgt.innerHTML) {
        ctl$('charshow').style.display = "none";
    }
    else {
        ctl$('charshow').style.display = "block";
        ctl$('charshow').innerHTML = tgt.innerHTML;
    }
}




function ReplaceText(str) {
    if(is_tail_space) {
        str += ' ';
    }

    // IE?
    if(proofframe.document.selection) {
        var sel = proofframe.document.selection;
        if(!sel || !sel.createRange) {
            return;
        }
        var ierange = sel.createRange();
        ierange.text = str;
        sel.empty();
    } else {
        var itop   = tatext.scrollTop;
        var istart = tatext.selectionStart;

        tatext.value = 
            tatext.value.substring(0, tatext.selectionStart) 
            + str + tatext.value.substring(tatext.selectionEnd);
        tatext.selectionEnd = 
            tatext.selectionStart = istart + str.length;
        tatext.scrollTop = itop;
    }
    set_text_size();
    tatext.focus();
}

function issync() {
    return pf$("is_sync").value == "1";
}

function eToggleSync() {
    pf$("is_sync").value = (issync() ? "0" : "1");
    pf$('icosync').src = issync()
        ? "/graphics/blusync.png"
        : "/graphics/brnsync.png";
}


// -- digraphs

var digraphs = {
     "a'" : "á",  "A'" : "À",
     "a!" : "à",  "A!" : "À",
     "a>" : "â",  "A>" : "Â",
     "a:" : "ä",  "A:" : "Ä",
     "a-" : "ā",  "A-" : "Ā",
     "a(" : "ă",  "A(" : "Ă",
     "aa" : "å",  "AA" : "Å",
     "a?" : "ã",  "A?" : "Ã",
     "a3" : "ǣ",  "A3" : "Ǣ",

     "A+" : "א",
     "B+" : "ב", "G+" : "ג", "D+" : "ד",
     "H+" : "ה", "W+" : "ו", "X+" : "ח",
     "Tj" : "ט", "J+" : "י", "K%" : "ך",
     "K+" : "כ", "L+" : "ל", "M%" : "ם",
     "M+" : "מ", "N%" : "ן", "N+" : "נ",
     "S+" : "ס", "E+" : "ע", "P%" : "ף",
     "P+" : "פ", "Zj" : "ץ", "ZJ" : "צ",
     "Q+" : "ק", "R+" : "ר", "Sh" : "ש",
     "T+" : "ת",

     "e'" : "é",  "E'" : "É",
     "e!" : "è",  "E!" : "È",
     "e>" : "ê",  "E>" : "Ê",
     "e:" : "ë",  "E:" : "Ë",
     "e-" : "ē",  "E-" : "Ē",
     "e(" : "ĕ",  "E(" : "Ĕ",
     "e?" : "ẽ",  "E?" : "Ẽ",

     "i'" : "í",  "I'" : "Í",
     "i!" : "ì",  "I!" : "Ì",
     "i>" : "î",  "I>" : "Î",
     "i:" : "ï",  "I:" : "Ï",
     "i-" : "ī",  "I-" : "Ī",
     "i(" : "ĭ",  "I(" : "Ĭ",
     "i?" : "ĩ",  "I?" : "Ĩ",

     "o'" : "ó",  "O'" : "Ó",
     "o!" : "ò",  "O!" : "Ò",
     "o>" : "ô",  "O>" : "Ô",
     "o:" : "ö",  "O:" : "Ö",
     "o-" : "ō",  "O-" : "Ō",
     "o(" : "ŏ",  "O(" : "Ŏ",
     "o?" : "õ",  "O?" : "Õ",
     "o/" : "ø",  "O/" : "Ø",

     "u'" : "ú",  "U'" : "Ú",
     "u!" : "ù",  "U`" : "Ù",
     "u>" : "û",  "U>" : "Û",
     "u:" : "ü",  "U:" : "Ü",
     "u-" : "ū",  "U-" : "Ū",
     "u(" : "ŭ",  "U(" : "Ŭ",
     "u?" : "ũ",  "U?" : "Ũ",

     "y'" : "ý",  "Y'" : "Ý",
     "y!" : "ỳ",  "Y`" : "Ỳ",
     "y>" : "ŷ",  "Y>" : "Ŷ",
     "y:" : "&#255;",  "Y:" : "Ÿ",

     "-o" : "º",  "-a" : "ª",
     "c," : "ç",  "C," : "Ç",
     "n?" : "ñ",  "N?" : "Ñ",
     "SE" : "§",  "DO" : "$",
     "ae" : "æ", "AE" : "Æ",
     "oe" : "œ", "OE" : "Œ",

     "'\"" : "˝", "+=" : "±",
     "''" : "´",  "'!" : "`",
     "d-" : "ð",  "D-" : "Ð",
     "th" : "þ",  "TH" : "Þ",

     ".M" : "·",  "*X" : "×",
     ":-" : "÷",

     "a*" : "α",  "A*" : "Α",
     "a%" : "ά",  "A%" : "Ά",
     ";!" : "ἂ",  ",!" : "ἃ",
     "?;" : "ἄ",  "?," : "ἅ",
     "!:" : "ἆ",  "?:" : "ἇ",
     "b*" : "β",  "B*" : "Β",
     "c*" : "ξ",  "C*" : "Ξ",
     "d*" : "δ",  "D*" : "Δ",
     "e*" : "ε",  "E*" : "Ε",
     "e%" : "έ",  "E%" : "Έ",
     "f*" : "φ",  "F*" : "Φ",
     "g*" : "γ",  "G*" : "Γ",
     "m3" : "ϝ",  "M3" : "Ϝ",
     "h*" : "θ",  "H*" : "Θ",
     "i*" : "ι",  "I*" : "Ι",
     "i%" : "ί",  "I%" : "Ί",
     "i3" : "ΐ",  "u3" : "ΰ",
     "j*" : "ϊ",  "J*" : "Ϊ",
     "j3" : "ϵ",  "J3" : "3",
     "k*" : "κ",  "K*" : "Κ",
     "k3" : "ϟ",  "K3" : "Ϟ",
     "l*" : "λ",  "L*" : "Λ",
     "m*" : "μ",  "M*" : "Μ",
     "n*" : "ν",  "N*" : "Ν",
     "o*" : "ο",  "O*" : "Ο",
     "o%" : "ό",  "O%" : "Ό",
     "p*" : "π",  "P*" : "Π",
     "p3" : "ϡ",  "P3" : "Ϡ",
     "q*" : "ψ",  "Q*" : "Ψ",
     "r*" : "ρ",  "R*" : "Ρ",
     "s*" : "σ",  "S*" : "Σ",
     "*s" : "ς",  "*S" : "Σ",
     "t*" : "τ",  "T*" : "Τ",
     "t3" : "ϛ",  "T3" : "Ϛ",
     "u*" : "υ",  "U*" : "Υ",
     "u%" : "ύ",  "U%" : "Ύ",
     "v*" : "ϋ",  "V*" : "Ϋ",
     "w*" : "ω",  "W*" : "Ω",
     "w%" : "ώ",  "W%" : "Ώ",
     "x*" : "χ",  "X*" : "Χ",
     "y*" : "η",  "Y*" : "Η",
     "y%" : "ή",  "Y%" : "Ύ",
     "z*" : "ζ",  "Z*" : "Ζ",
     "g," : "ģ",  "G," : "Ģ",

     "<<" : "«", ">>" : "»",

     "0S" : "⁰", "1S" : "¹",
     "2S" : "²", "3S" : "³", "4S" : "⁴", "5S" : "⁵",
     "6S" : "⁶", "7S" : "⁷", "8S" : "⁸", "9S" : "⁹",
     "12" : "½", "14" : "¼", "34" : "¾",
     "18" : "⅛", "38" : "⅜", "58" : "⅝", "78" : "⅞",
     "13" : "⅓", "23" : "⅔", "16" : "⅙", "56" : "⅚",
     "15" : "⅕", "25" : "⅖", "35" : "⅗", "45" : "⅘",

     '"6' : "“", '"9' : "”", "'6" : "‘", "'9" : "’",
     "DG" : "°"
};

function digraph(c) {
    if(digraphs[c]) {
        return digraphs[c];
    }
    else {
        return null;
    }
}

function eKeyDown(e) {
    var kCode;
    if(!e) { e = window.event; }

    pause_wordchecking();

    kCode = (e.which && typeof e.which == "number") 
        ? e.which 
        : e.keyCode;

    console.debug("keydown", kCode);

    if(kCode == 8 && keystack.length == 1) {
        keystack.push(8);
    }

    return true;
}

/*
function eCharValue(e) {
    if(!e) e = document.parentWindow.event;
    if(!e.ctrlKey) return;
    if(! tatext) return;
    var b = SelectionBounds();
    var c = tatext.value[b.start];
    alert(c + " 0x" + c.charCodeAt(0).toString(16).toUpperCase());
}
*/

function eKeyPress(e) {
    if(!e) { e = window.event; }
    var kCode = (e.which && typeof e.which == "number") 
                ? e.which : e.keyCode;
    var kChar = e.charCode;

    console.debug("keyPress", kChar);
    switch (kCode) {
    case 8:
        // defer to keydown for backspace trapping
        return true;

    case 16: // IE passes the shift key, ignore it
        return true;

    default:
        switch (keystack.length) {
            case 1:
                // legitimate character, replace old one
                keystack[0] = kCode;
                return true;

            case 0:
                // no character yet, load the queue
                console.debug("zero push ".kCode);
                keystack.push(kCode);
                return true;

            case 2:
                // sb a character and a backspace
                if(keystack.pop() != 8) {
                    // error - reinit queue
                    keystack = [kCode];
                    return true;
                }
                keystack.push(kCode);
                break;

            default:    // error
                console.debug("error keystack length "
                    + keystack.length.toString() 
                    + " (" + keystack.toString() + ")");
                keystack = [kCode];
                return true;
        }
    }

    // should only get here if collecting char 2
    // time to fire digraph
    var char1 = String.fromCharCode(keystack[0]);
    var char2 = String.fromCharCode(keystack[1]);
    var key = char1 + char2;

    var mappedChar = digraph(key);

    if(! mappedChar) {
        return true;
    }

    var val = tatext.value;
    if(typeof tatext.selectionStart == "number" 
        && typeof tatext.selectionEnd == "number") {
        // Non-IE browsers and IE 9
        var itop     = tatext.scrollTop;
        var start    = tatext.selectionStart;
        var end      = tatext.selectionEnd;
        tatext.value = val.slice(0, start) + mappedChar + val.slice(end);

        // Move the caret
        tatext.selectionStart = tatext.selectionEnd = start + 1;
        tatext.scrollTop    = itop;
    }
    else if(proofframe.document.selection 
            && proofframe.document.selection.createRange) {
        // For IE up to version 8
        var selectionRange  = proofframe.document.selection.createRange();
        var textInputRange  = tatext.createTextRange();
        var precedingRange  = tatext.createTextRange();
        var bookmark        = selectionRange.getBookmark();
        textInputRange.moveToBookmark(bookmark);
        precedingRange.setEndPoint("EndToStart", textInputRange);
        start               = precedingRange.text.length;
        end                 = start + selectionRange.text.length;
        tatext.value        = val.slice(0, start) + mappedChar + val.slice(end);
        start++;

        // Move the caret
        textInputRange      = tatext.createTextRange();
        textInputRange.collapse(true);
        textInputRange.move("character", start - (tatext.value.slice(0, start).split("\r\n").length - 1));
        textInputRange.select();
    }

    console.debug("keypress returning false");
    return false;
}

// std

function eSetImageUrl(url) {
    document.getElementById('scanimage') 
        .src = url;
}

function eReplacedImageFile() {
    imgpage.src = imgpage.src;   
    eHideUpload();
}

function eHideUpload() {
    pf$('uploadframe').style.display = 'none';
}

function eShowUpload() {
    pf$('uploadframe').style.display = 'block';
}

// file has been selected
function eUpFile() {
    pf$('uploadframe').contentDocument.upform 
        .upbutton.style.display='inline-block';
}
function eQuitUpload() {
    top.eHideUpload();
}

function eUp() {
    pf$('uploadframe').contentDocument.upform 
        .upbutton.style.display='none';
    pf$('uploadframe').contentDocument
        .getElementById('uploading').style.display='inline';
}

function translate(str) {
    return str;
}

// needs to ajax for translation
function AreYouSure(question) {
    return(confirm(translate(question)));
}

function ReplaceUrl(url) {
    window.location.replace(url);
}

function eDrop(e) {
    if(!e) { e = window.event; }
    var tgt = e.target ? e.target : e.srcElement;
    if(tgt.options[tgt.selectedIndex].value == 0) {
        return;
    }
    var c = tgt.options[tgt.selectedIndex].text;
    InsertChar(c);
    tgt.selectedIndex = 0;
    return false;
}

function IsSelectedText() {
    if(!tatext) {
        return false;
    }
    return tatext.value.length > 0;
}

// return whatever text is selected in textarea
function SelectedText() {
    var sel;
    var seltext;
    var ierange;
    if(!tatext) {
        return '';
    }
    if(!tatext.value.length) {
        return '';
    }

    // if(textframe && textframe.document.selection)
    if(proofframe.document.selection) {
        sel = proofframe.document.selection;
        if(!sel ||  !sel.createRange) {
            return '';
        }
        ierange = sel.createRange();
        seltext = ierange.text;
    } else if(tatext.selectionEnd) {
        seltext = tatext.value.substring(
                tatext.selectionStart, tatext.selectionEnd);
    } else {
        return '';
    }

    if(!seltext || !seltext.length) {
        return '';
    }

    is_tail_space = (seltext.charAt(seltext.length-1) == ' ');
    if(is_tail_space) {
        seltext = seltext.substring(0, seltext.length-1);
    }
    return seltext;
}

function eSetFootnote() {
    var sel = SelectedText();
    var re = /\s/; 
    var txt = '[Footnote ' + sel.replace(re, ': ') + ']';
    ReplaceText(txt);
    return false;
}

function eSetGreek() {
    var sel = SelectedText();
    var re = /\s/;
    var txt = '[Greek: ' + sel + ']';
    ReplaceText(txt);
    return false;
}

function eSetIllustration() {
    var sel = SelectedText();
    var re = /\s/;
    var txt = '[Illustration: ' + sel + ']';
    ReplaceText(txt);
    return false;
}

function eInsertThoughtBreak() {
    ReplaceText("\n<tb>\n");
    return false;
}

function eSetBlankPage() {
    tatext.value = "[Blank Page]";
    set_text_size();
    return false;
}

function eSetNote() {
    var sel = SelectedText();
    var re = /\s/;
    var txt = '[** ' + sel + ']';
    ReplaceText(txt);
    return false;
}

function eSetBraces() {
    var sel = SelectedText();
    var re = /\s/;
    var txt = '{' + sel + '}';
    ReplaceText(txt);
    return false;
}

function eSetBrackets() {
    var sel = SelectedText();
    var re = /\s/;
    var txt = '[' + sel + ']';
    ReplaceText(txt);
    return false;
}

function eSetParens() {
    var sel = SelectedText();
    var re = /\s/;
    var txt = '(' + sel + ')';
    ReplaceText(txt);
    return false;
}

function eSetSmallCaps() {
    var sel = SelectedText();
    ReplaceText('<sc>' + sel + '</sc>');
    return false;
}

var acommon = ['and','of','the','in','on','de',
        'van','am','pm','bc','ad','a',
        'an','at','by','for','la','le'];

function eSetTitleCase() {
    var aword;
    var sel = SelectedText();
    if(!sel || !sel.length) {
        return false;
    }
    sel = sel.toLowerCase();
    sel = sel.charAt(0).toUpperCase() + sel.substr(1);
    if(sel.length <= 1) {
        ReplaceText(sel);
        return false;
    }

    sel = sel.replace(/\b\w/g, function(str) {
        return str.toUpperCase();
    });

    for (aword in acommon) {
        var expr = '\\\\b' + aword + '\\\\b';
        var re = new RegExp(expr, 'gi');
        sel = sel.replace(re,
            function(str) { return str.toLowerCase(); });
    }
    ReplaceText(sel);
    return false;
}

function eSetAntiqua() {
    var sel = SelectedText();
    ReplaceText('<f>' + sel + '</f>');
    return false;
}

function eSetGuillemets() {
    var sel = SelectedText();
    ReplaceText('«' + sel + '»');
    return false;
}

function eSetGesperrt() {
    var sel = SelectedText();
    ReplaceText('<g>' + sel + '</g>');
    return false;
}

function eSetUpperCase() {
    var sel = SelectedText();
    if(sel.length) {
        ReplaceText(sel.toUpperCase());
    }
    return false;
}

function eSetLowerCase() {
    var sel = SelectedText();
    if(sel.length) {
        ReplaceText(sel.toLowerCase());
    }
    return false;
}

function eRemoveMarkup() {
    var s = SelectedText();
    if(s.length) {
        ReplaceText(s.replace(/<\/?[^>]+(>|$)/g,''));
    }
    return false;
}

function NewBlankWindow() {
    return window.open();
}

function NewWindow(url, name, height, width) {
    return window.open(url, name,
                    "height=" + height,
                    "width=" + width,
                    "directories=no",
                    "location=no",
                    "menubar=no",
                    "resizable=yes",
                    "scrollbars=no",
                    "status=no",
                    "titlebar=no",
                    "toolbar=no");
}

function eSetBold() {
    var sel = SelectedText();
    ReplaceText('<b>' + sel + '</b>');
    return false;
}

function eSetItalics() {
    var sel = SelectedText();
    ReplaceText('<i>' + sel + '</i>');
    return false;
}

function eSetNoWrap() {
    var sel = SelectedText();
    ReplaceText('/*\n' + sel + '\n*/');
    return false;
}

function eSetBlockQuote() {
    var sel = SelectedText();
    ReplaceText('\n/#\n' + sel + '\n#/\n');
    return false;
}

function eLinkLayout() {
    ajaxSwitchLayout();
    return false;
}

function eTextLeft() {
    var lm = tatext.style.paddingLeft 
        ? parseInt(tatext.style.paddingLeft, 10)
        : 0;
    if(lm > 0) {
        divpreview.style.paddingLeft =
        tatext.style.paddingLeft = (lm - 1).toString() + "%";
    }
}

function eTextRight() {
    var lm = tatext.style.paddingLeft 
        ? parseInt(tatext.style.paddingLeft, 10)
        : 0;
    if(lm < 20) {
        divpreview.style.paddingLeft =
        tatext.style.paddingLeft = (lm + 1).toString() + "%";
    }
}

function eLinkSearch() {
}

function ajaxSwitchLayout() {
    var qry = {};
    qry['querycode']    = "switchlayout";

    writeAjax(qry);
    return false;
}

function FontFace() {
    return pf$('selfontface') 
        .item(pf$('selfontface').selectedIndex) 
            .value;
}

function eSetFontFace() {
    divpreview.style.fontFamily =
    tatext.style.fontFamily     = FontFace();
    set_text_size();
    ajaxSetFontFace();
    return false;
}

function ajaxSetFontFace() {
    var qry = {};
    qry['querycode']    = "setfontface";
    qry['data']         = FontFace();

    writeAjax(qry);
    return false;
}

function FontSize() {
    return pf$('selfontsize') 
        .item(pf$('selfontsize').selectedIndex) 
            .value;
}

function ApplyFontSize() {
    divpreview.style.fontSize = tatext.style.font;
    tatext.style.fontSize     = FontSize();
    set_text_size();
    return false;
}

function eSetFontSize() {
    divpreview.style.fontSize =
    tatext.style.fontSize     = FontSize();
    set_text_size();
    ajaxSetFontSize(FontSize());
    return false;
}

function ajaxSetFontSize(size) {
    var qry = {};
    qry['querycode']    = "setfontsize";
    qry['data']         = size;

    writeAjax(qry);
    return false;
}

function ajaxSetZoom(value) {
    var qry = {};
    qry['querycode']    = "setzoom";
    qry['data']         = value;

    writeAjax(qry);
    return false;
}

function PreviewFormat() {
    var d = NewBlankWindow().document;
        d.write(""
            + tatext.value
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;')
                .replace(/&lt;(\/?)(i|b|hr)&gt;/ig, '<$1$2>')
                .replace(/&lt;sc&gt;/ig,
                    '<span style="font-variant: small-caps;">')
                .replace(/&lt;\/sc&gt;/ig, '</span>')
            + "");
    d.close();
    return false;
}

/*
function SetWrap(b_wrap) {
    var iarea = tatext;
    var wrap_setting = b_wrap ? 'soft' : 'off';
    var oset = iarea.getAttribute('wrap');
    iarea.setAttribute('wrap', wrap_setting);
    var parNod = iarea.parentNode;
    var nxtSib = iarea.nextSibling;
    parNod.removeChild(iarea);
    parNod.insertBefore(iarea, nxtSib);
    set_text_size();
    return false;
}

function Wrap() {
    var iarea = tatext;
    return (iarea.getAttribute('wrap') == 'soft');
}
*/

function eZoomIn() {
    var w = formedit.zoom.value;
    w = w ? w * 1.03 : 100;
    if(w > 400) {
        w = 400;
    }
    imgpage.style.width = w + "%";
    formedit.zoom.value = w.toString();
    ajaxSetZoom(w);
    return false;
}

function eZoomOut() {
    var w = formedit.zoom.value;
    w = w ? w * 0.97 : 90;
    if(w < 25) {
        w = 25;
    }
    imgpage.style.width = w + "%";
    formedit.zoom.value = w.toString();
    ajaxSetZoom(w);
    return false;
}

function eTextPlus() {
    var sz = parseInt(pf$('fntSize').value, 10);
    if(sz >= font_sizes.length) {
        return true;
    }
    sz++;
    divpreview.style.fontSize =
    tatext.style.fontSize     = font_sizes[sz];
    set_text_size();
    pf$('fntSize').value        = sz;
    return true;
}

function eTextMinus() {
    var sz = parseInt($('fntSize').value, 10);
    if(sz <= 0) {
        return true;
    }
    sz--;
    divpreview.style.fontSize =
    tatext.style.fontSize     = font_sizes[sz];
    set_text_size();
    pf$('fntSize').value        = sz;
    return true;
}

function eSaveTemp() {
    var qry = {};
    qry['querycode']    = "savetemp";
    qry['projectid']    = formedit.projectid.value;
    qry['pagename']     = formedit.pagename.value;
    qry['text']         = tatext.value;

    writeAjax(qry);
    return false;
}

function eSaveNext() {
    eMaybeAccept();
    formedit.todo.value = 'savenext';
    formedit.submit();
}

function eSaveQuit() {
    eMaybeAccept();
    formedit.todo.value = 'savequit';
    formedit.submit();
}

function eMaybeAccept() {
    var accepts = span_id_array();
    if(accepts.length > 0) {
        if(AreYouSure("Save "+accepts.length.toString()
                                    + " accepted words?")) {
            awcAccept();
        }
    }
}

function eQuit() {
    eMaybeAccept();
    formedit.todo.value = 'quit';
    formedit.submit();
}

function eReturnPage() {
    if(AreYouSure("Return page and lose your changes?")) {
        formedit.todo.value = "returnpage";
        formedit.submit();
    }
}

function point_in_obj(obj, ptX, ptY) {
    var x1 = 0;
    var x2 = 0;
    var y1 = 0;
    var y2 = 0;
    for(var o = obj; o ; o = o.offsetParent) {
        x1 += (o.offsetLeft - o.scrollLeft);
        y1 += (o.offsetTop - o.scrollTop);
    }
    x2 = x1 + obj.offsetWidth;
    y2 = y1 + obj.offsetHeight;
    return ptX >= x1 && ptX <= x2
        && ptY >= y1 && ptY <= y2;
}

/*
function eTextSelect(e) {
    if(!e) { e = window.event; }
    if(proofframe.document.selection 
                && proofframe.selection.createRange) {
        _range = proofframe.document.selection.createRange();
    }
}
*/

function eTextFocus(e) {
    if(!e) { e = window.event; }
    _scroll_focus = divfratext;
}

function eTextBlur(e) {
    if(!e) { e = window.event; }
    _scroll_focus = null;
}

function eImgFocus(e) {
    if(!e) { e = window.event; }
    _scroll_focus = divimage;
}

function eImgBlur(e) {
    if(!e) { e = window.event; }
    _scroll_focus = null;
}

function eTextClick(e) {
    if(!e) { e = window.event; }
    var ispan;
    var spans = divpreview.getElementsByTagName("SPAN");
    var eX = e.clientX;
    var eY = e.clientY;
    for(var i = 0; i < spans.length; i++) {
        var sp = spans[i];
        if(point_in_obj(sp, eX, eY)) {
            ispan = sp;
            break;
        }
    }

    if(! ispan) {
        return true;
    }

    var id = ispan.id;
    if(_span_ids[id] && _span_ids[id] == "accepted") {
        ispan.className = _span_ids[id] = "wc";
    }
    else {
        ispan.className = _span_ids[id] = "accepted";
    }
    return true;
}

function get_flags() {
    var txt     = tatext.innerHTML;
    var re      = /<span [^>]*?<\/span>/g;
    var aflags  = re(txt);
    return aflags;
}

function eMouseMove(e) {
    if(!e) { e = window.event; }
    var _sync_x = e.clientX;
    var _sync_y = e.clientY;
    // console.debug("mouse x,y:", e.clientX, e.clientY);
    if(xy_in_divfratext(_sync_x, _sync_y)) {
        if(_active_scroll_id != "divfratext") {
            _active_scroll_id = "divfratext";
            // console.debug("mouse position to divfratext");
        }
    }
    else if(xy_in_divimage(_sync_x, _sync_y)) {
        if(_active_scroll_id != "divimage") {
            _active_scroll_id = "divimage";
            // console.debug("mouse position to divimage");
        }
    }
    else {
        if(_active_scroll_id != null) {
            _active_scroll_id = null;
            // console.debug("mouse position to null");
        }
    }
}

function xy_in_divfratext(x, y) {
    var top = divfratext.offsetTop;
    var bottom = top + divfratext.offsetHeight;
    var left = divfratext.offsetLeft;
    var right = divfratext.offsetLeft + divfratext.offsetWidth;
    return x >= left && x <= right && y >= top && y <= bottom;
}

function xy_in_divimage(x, y) {
    var top = divimage.offsetTop;
    var bottom = top + divimage.offsetHeight;
    var left = divimage.offsetLeft;
    var right = divimage.offsetLeft + divimage.offsetWidth;
    return x >= left && x <= right && y >= top && y <= bottom;
}


// copy scroll psn from one element to another
function apply_scroll_pct(fromctl, toctl) {
    if(! issync()) {
        return;
    }
    var fromrange = fromctl.scrollHeight - fromctl.offsetHeight;
    if(fromrange <= 0) {
        return;
    }
    var pct = 100 * fromctl.scrollTop / fromrange;
    var torange = toctl.scrollHeight - toctl.clientHeight;
    if(torange <= 0) {
        return;
    }
    if(toctl.scrollTop == torange * pct / 100) {
        return;
    }
    toctl.scrollTop = torange * pct / 100;
}

function eScroll(e) {
    if(! issync()) {
        return;
    }
    if(! e) e = window.event;
    var tgt = e.currentTarget ? e.currentTarget : e.srcElement;
    // console.debug("eScroll ", tgt.id);
    if(tgt.id == "divfratext") {
        if(_active_scroll_id == "divfratext") {
            // source is divfratext, also scroller, apply to divimage
            apply_scroll_pct(divfratext, divimage);
        }
    }
    else if(tgt.id == "divimage") {
        if(_active_scroll_id == "divimage") {
            apply_scroll_pct(divimage, divfratext);
        }
    }
    return true;
}

/*
function eImgScroll(e) {
    if(! e) e = window.event;
    console.debug("imgscroll ", proofframe.document.activeElement.id);
    if(issync() && _scroll_focus == divimage) {
        apply_scroll_pct(divimage, divfratext);
    }
}

function eTextScroll(e) {
    if(! e) e = window.event;
    console.debug("divscroll ", proofframe.document.activeElement.id);
    textrange = divfratext.scrollHeight - divfratext.offsetHeight;
    imgrange  = divimage.scrollHeight - divimage.offsetHeight;
    if(_scroll_focus == divtext) {
        return;
    }
    else if(_scroll_focus == null) {
        _scroll_focus = divtext;
        apply_scroll_pct(divfratext, divimage);
    }
    else if(_scroll_focus == divimage) {
        if(

    if(textrange == 0 || imgrange == 0) {
        return;
    }
    if(issync() && _scroll_focus == divimage) {
    }
}
*/

function eResize() {
    applylayout(null);
    // console.debug("resize");
}

function set_wordchecking() {
    // divpreview.style.visibility     = "visible";
    divctlwc.style.display          = "inline";
    // divctlnav.style.display         = "inline";
    pf$("imgwordcheck").src         = "gfx/wchk-on.png";
    is_wordchecking = true;
    _wc_wakeup = 0;
}

function pause_wordchecking() {
    if(! is_wordchecking)
        return;
    divpreview.style.visibility     = "hidden";
    // advance the token in case a wordcheck is running--
    // response will be ignored if the token has advanced.
    _wc_token++;
    // if there is no pause in place
    if(_wc_wakeup == 0) {
        // init pause and timer
        _wc_wakeup = _date.getTime() + 4000;
        window.setTimeout(resume_wordchecking, 4000);
    }
    else {
        // there is a pause; push it out
        _wc_wakeup = _date.getTime() + 2000;
    }
}

function resume_wordchecking() {
    // is there a pause? No? just return
    if(_wc_wakeup == 0) {
        return;
    }
    // is there time left on the pause?
    var delta = _wc_wakeup - _date.getTime();
    if(delta < 0) {
        // not expired - has been extended - leave for another
        return;
    }
    else {
        // it's timed out - cancel pause and submit a wordcheck
        // (which will handle token)
        _wc_wakeup = 0;
        awcWordcheck();   
    }
}

function clear_wordchecking() {
    if(is_wordchecking) {
        is_wordchecking                = false;
        _wc_wakeup                      = 0;
        divctlwc.style.display          = "none";
        // divctlnav.style.display         = "inline";
        pf$("imgwordcheck").src         = "gfx/wchk-off.png";
    }
}


/*
function ePreviewClick(e) {
    if(! is_wordchecking)
        return true;
    if(!e) e = window.event;
    var t = SpanFromXY(e.clientX, e.clientY);

    // user clicked a span or elsewhere in text
    if(t.nodeName.toLowerCase() != "span") {
        return true;
    }

    // check if clicked span is already accepted
    var id = t.id.replace(/^span/i, "wc");
    if(ok_spans[id] && ok_spans[id] != '') {
        // if so toggle color (cancel sug) and remove array value
        t.className = "wc";
        ok_spans[id] = '';
    }
    else {
        // otherwise toggle color (set sug) and set array word value
        t.className = "accepted";
        ok_spans[id] = t.innerHTML;
    }
    return true;
}

function SpanFromXY(x, y) {
    var d = tatext.style.display = "none";
    var el = document.elementFromPoint(x, y);
    tatext.style.display = d;
    return el;
}

*/

function set_scroll_pct(ctl, pct) {
    if(pct <= 0) {
        return;
    }

    var torange = ctl.scrollHeight - ctl.clientHeight;
    if(torange <= 0) {
        return;
    }

    ctl.scrollTop = torange * pct / 100;
}

function eImgClick(e) {
    if(!e) { e = window.event; }
    var t = e.target ? e.target : e.srcElement;
    if(t.nodeName.toLowerCase() != "img") {
        return;
    }
}

// when hovering over the image +/- buttons,
// the mouse wheel zooms the image
// up (> 0) zoom in, down (< 0) zoom out

function eWheel(e) {
    var t;
    if(!e) e = window.event;

    var tgt = e.currentTarget ? e.currentTarget : e.srcElement;

    return true;
}

function eImgCtlWheel(e) {
    if(!e) { e = window.event; }
    if(e.wheelDelta) {
        if(e.wheelDelta > 0)
        {
           top.ZoomIn();
        } else {
            top.ZoomOut();
        }
    }
    else if(e.detail) {
        if(e.detail > 0) {
           top.ZoomOut();
        } else {
            top.ZoomIn();
        }
    }
    return false;
}

// function set_context_word(w) {
    // qry = {};
    // qry['querycode'] = 'wordcontext';
    // qry['projectid'] = document.formcontext.projectid.value;
    // qry['word']      = w;
    // writeAjax(qry);
// }

// user clicks a list word to choose a context set
// the option element for the word has value w_ + the word
function eTblContextChange(e) {
    sync_context();
    return true;
}

function sync_context() {
    var t = document.formcontext.tblcontext;
    if(! t) {
        return;
    }
    if(t.value.length <= 2) {
        return;
    }

    // var imgc = document.getElementById("imgcontext");
    // if(imgc) {
        // imgc.style.display = "none";
    // }

    var w = t.value.substr(2);
    qry = {};
    qry['querycode'] = 'wordcontext';
    qry['projectid'] = document.formcontext.projectid.value;
    qry['word']      = w;
    writeAjax(qry);
}

// json response handler for wccontext
// builds the word list for context selection
function ajxDisplayContextWords(rsp) {
    var i;
    if(_active_ctl) {
        _active_ctl = null;
    }
    str = "<tbody>\n";
    for (i = 0; i < rsp.length; i++) {
        var wrd = rsp[i][0];
        var n   = rsp[i][1];
        str = str + "<tr><td id='w_" + wrd + "' class='likealink'"
                + " style='background-color: white;'>"
                + wrd + "</td><td>" + n + "</td></tr>\n";
    }
    str += "</tbody>\n";
    pf$("tblcontext").innerHTML = str;
}

// json response handler for wordcontext
// fills top box with contexts from json
// response has array of pagename, lineindex, linecount, context
function ajxDisplayContextList(rsp) {
    var i = 0;
    var str = "";
 
    if(! $("div_context_list")) {
        return;
    }
    _contexts = rsp.contextinfo.contexts;
    for(i = 0; i < _contexts.length; i++) {
        var ctxt = _contexts[i];
        var id = i.toString();
        str = str + "<a id='" + id + "'"
                        + " class='likealink'"
                        + " onclick='eSetContext(" + id + ")'>"
                        + "page " + ctxt.pagename
                        + " (line " + ctxt.lineindex.toString()
                        + " of " + ctxt.linecount.toString() + ")"
                        + "</a>"
                  + "<pre class='ctxt'>" + ctxt.context + "</pre>\n";
    }
    $("div_context_list").innerHTML = str;
    eSetContext("0");
}

function eLangcode(e) {
    if(!e) { e = window.event; }
    var tgt = e.target ? e.target : e.srcElement;
    formedit.langcode.value = tgt.value;
    awcWordcheck();
}

function eWordList(e) {
    awcWordList();
}

function SetAllCheck(val) {
    var i;
    var row;
    var tbl = pf$('tblcontext');
    for (i = 0; i < tbl.rows.length; i++) {
        row = tbl.rows[i];
        if(c = row.getElementsByTagName('input')[0]) {
            c.checked = val;
        }
    }
}

function eCheckAll() {
    SetAllCheck(true);
}

function eUncheckAll() {
    SetAllCheck(false);
}

// user clicked something on the context form
function eFormContextClick(e) {
    if(!e) { e = window.event; }
    var t = (e.originalTarget ? e.originalTarget : e.srcElement);
    switch (t.name) {
        case "btncheck":
            eCheckAll();
            break;

        case "btnuncheck":
            eUncheckAll();
            break;

        case "btnmark":
            set_word_disposition(t.value);
            break;

        default:
    }
}

function set_word_disposition(value) {
    switch(value) {
        case "good":
        case "bad":
        case "delete":
    }
}

// body load event for wordcontext page
// we have projectid, language, and which list type.
// need to pull list and select first word and context.
function eContextInit() {
    formcontext = document.formcontext;

    addEvent(formcontext.btndelete, "click", eDeleteWordClick);
    addEvent(formcontext.btngood,   "click", eGoodWordClick);
    addEvent(formcontext.btnbad,    "click", eBadWordClick);

    formcontext.btndelete.style.display = 
        (formcontext.mode.value == "good"
        || formcontext.mode.value == "bad") ? "block" : "none";
    formcontext.btngood.style.display = 
        (formcontext.mode.value == "good") ? "none" : "block";
    formcontext.btnbad.style.display = 
        (formcontext.mode.value == "bad") ? "none" : "block";
    sync_context();
    // var wrd = formcontext.tblcontext.value.substr(2);
    // set_context_word(wrd);
}

function eGoodWordClick(e) {
    var i = formcontext.tblcontext.selectedIndex;
    if(i >= 0) {
        awcAddGoodWord(i);
        formcontext.tblcontext.remove(i);
        formcontext.tblcontext.selectedIndex = i;
        sync_context();
    }
}

function eGoodWordClick(e) {
    var i = formcontext.tblcontext.selectedIndex;
    if(i >= 0) {
        awcAddGoodWord(i);
        formcontext.tblcontext.remove(i);
        formcontext.tblcontext.selectedIndex = i;
        sync_context();
    }
}

function eBadWordClick(e) {
    var i = formcontext.tblcontext.selectedIndex;
    if(i >= 0) {
        awcAddBadWord(i);
        formcontext.tblcontext.remove(i);
        formcontext.tblcontext.selectedIndex = i;
        sync_context();
    }
}

function awcAddGoodWord(i) {
    var qry = {};
    qry['querycode']    = "addgoodword";
    qry['projectid']    = formcontext.projectid.value;
    qry['langcode']     = formcontext.langcode.value;
    qry['word']         = formcontext.tblcontext.options[i]
                            .value.substr(2);
    writeAjax(qry);
}

function awcAddBadWord(i) {
    var qry = {};
    qry['querycode']    = "addbadword";
    qry['projectid']    = formcontext.projectid.value;
    qry['langcode']     = formcontext.langcode.value;
    qry['word']         = formcontext.tblcontext.options[i]
                            .value.substr(2);
    writeAjax(qry);
}

function eDeleteWordClick() {
}


// select another language
function eLangPick() {
    awcContext();
}

// select another wordlist type
function eListPick() {
    awcContext();
}

function eImgWheel() {
    // apply_scroll_pct(divimage, divpreview);
    // apply_scroll_pct(divimage, tatext);
}

function ePreviewWheel() {
    // apply_scroll_pct(divpreview, divimage);
}

function eTextWheel() {
    // apply_scroll_pct(tatext, divimage);
}

function active_context() {
    return _contexts.length > 0
        ? _contexts[_active_context_index] 
        : null;
}

function eContextImgLoad() {
    var context_image_scroll_pct = 
        (active_context() && (active_context().lineindex > 0))
            ? 100 * active_context().lineindex 
                                / active_context().linecount 
            : -1;
    $('imgcontext').style.display = "block";
    set_scroll_pct($('div_context_image'), context_image_scroll_pct);
}

// consequence of table item onclick (ref this module only)
function eSetContext(index) {
    _active_context_index = index;
    $('imgcontext').style.display = "none";
    $('imgcontext').src = active_context()
                        ? active_context().imageurl
                            .replace(/\&amp;/, "&")
                        : "";
}

function awcContext() {
    var qry = {};
    qry['querycode']    = "wccontext";
    qry['projectid']    = formcontext.projectid.value;
    qry['langcode']     = formcontext.langcode.value;
    qry['mode']         = formcontext.mode.value;
    writeAjax(qry);

}

function awcAccept() {
    var qry = {};
    qry['querycode']    = "wcaccept";
    qry['projectid']    = formedit.projectid.value;
    qry['pagename']     = formedit.pagename.value;
    qry['langcode']     = formedit.langcode.value;
    qry['acceptwords']  = span_id_array();
    writeAjax(qry);
}

// initiate wordcheck transaction
function awcWordcheck() {
    var qry = {};

    qry['querycode']    = "wctext";
    qry['token']        = ++_wc_token;
    qry['projectid']    = formedit.projectid.value;
    qry['pagename']     = formedit.pagename.value;
    qry['langcode']     = formedit.langcode.value;
    qry['text']         = tatext.value;
    set_wordchecking();
    writeAjax(qry);
}

function awcWordList() {
    var qry = {};
    qry['querycode']    = "wcwordlist";
    qry['projectid']    = formedit.projectid.value;
    qry['pagename']     = formedit.pagename.value;
    qry['langcode']     = formedit.langcode.value;
    // qry['wordlist']     = formedit.wordlist.value;
    qry['text']         = tatext.value;
    writeAjax(qry);
}

// user clicks wc button
// 1. initial wordcheck,
// 2. wordchecking, and wants to edit
// 3. editing, and wants to (resume) wordcheck.

function eWordCheck() {
    // turn it off? Send accepted list
    if(is_wordchecking) {
        divpreview.style.visibility     = "hidden";
        awcAccept();
    }
    else {
        awcWordcheck();
    }
    return false;
}

// process wordcheck response
function show_wordcheck(rsp) {
    var wclass;
    // wordchecking cancelled?
    if(! is_wordchecking) {
        return;
    }
    // token match?
    if(_wc_token != rsp.token) {
        return;
    }
    _wc_response    = rsp;
    var wccount     = 0;
    var wc_words    = rsp.wcwords;
    var srctext     = tatext.value;
    var trows       = srctext.split(/\n/);
    for(var i = 0; i < wc_words.length; i++) {
        var wl = wc_words[i];
        var word  = wl[0];
        var line  = wl[1];
        var row   = line - 1;
        if(wl[2] && wl[2] == '*suggested') {
            wclass = "wcs";
        }
        else {
            wclass = "wc";
            wccount++;
        }
        var expr  = '\\b(' + word + ')\\b';
        var re    = new RegExp(expr, 'gi');
        var trow  = trows[row];
        trows[row] = trow.replace(re,
            '<span id="wc_'+word+'_'+line
              +'" class="'+wclass+'">$1</span>');
    }
    pf$("span_wccount").innerHTML = wccount;
    var pvtext = trows.join("\n");
    divpreview.innerHTML = pvtext
        .replace(/<(\/?).>/g,  "&lt;$1i&gt;");
    for(var id in _span_ids) {
        var item = pf$(id);
        if(! item) {
            delete _span_ids[id];
        }
            
        if(item) {
            if(_span_ids[id] == "accepted") {
                item.className = _span_ids[id];
            }
            else {
                _span_ids[id] = item.className;
            }
        }
    }
    divpreview.style.visibility     = "visible";
}

function eWCMonitor(msg) {
    var rsp = JSON.parse(msg);
    switch (rsp.querycode) {
    case 'savetemp':
        alert(rsp.alert);
        break;

    case 'wctext':
        show_wordcheck(rsp);
        break;

    // response from submitting accepted words leaving wc mode
    case 'wcaccept':
        clear_wordchecking();
        break;

    case 'wccontext':
        ajxDisplayContextWords(rsp.wordarray);
        break;

    case 'wordcontext':
        ajxDisplayContextList(rsp);
        break;

    case 'setfontsize':
    case 'setfontface':
    case 'setzoom':
    case 'acceptwords':
    case 'addgoodword':
    case 'addbadword':
    case 'deleteword':
        break;

    case 'switchlayout':
        formedit.layout.value = rsp.layout;
        formedit.imgpct = rsp.imgpct;
        pf$('switchlayout').src = 
            (rsp.layout == "horizontal")
                ? "gfx/horiz.png"
                : "gfx/vert.png";
        applylayout(rsp);
        break;

    default:
        window.alert("unknown querycode: " + rsp);
        break;
    }
}

function span_id_array() {
    var a = [];
    var i = 0;

    for(var id in _span_ids) {
        if(_span_ids[id] == "accepted") {
            a[i++] = id.replace(/(^wc_|_\d+$)/g, "");
        }
    }
    return a;
}

function SetFontSizeSelector(size) {
    var i;
    var sel = pf$('selfontsize');
    for (i = 0; i < sel.options.length; i++) {
        var o = sel.options[i];
        if(o.value == size) {
            sel.selectedIndex = o.index;
            break;
        }
    }
}

function SetFontFaceSelector(size) {
    var i;
    var sel = pf$('selfontface');
    for (i = 0; i < sel.options.length; i++) {
        var o = sel.options[i];
        if(o.value == size) {
            sel.selectedIndex = o.index;
            break;
        }
    }
}

/*
http://af-design.com/blog/2008/03/14/rfc-3986-compliant-uri-encoding-in-javascript/
String.prototype.to_rfc3986 = function (){
   var tmp =  encodeURIComponent(this);
   tmp = tmp.replace('!','%21');
   tmp = tmp.replace('*','%2A');
   tmp = tmp.replace('(','%28');
   tmp = tmp.replace(')','%29');
   tmp = tmp.replace("'",'%27');
   return tmp;
*/

function initAjax() {
    if(window.XMLHttpRequest) {
        ajax = new XMLHttpRequest();
    }
    else {
        ajax = new ActiveXObject("Microsoft.XMLHTTP");
    }
    ajaxActionFunc = eWCMonitor;
    ajax.onreadystatechange = readAjax;
}

function writeAjax(a_args) {
    // php end will rawurldecode this to recover it
    var jq = 'jsonqry=' + encodeURIComponent(JSON.stringify(a_args));
    initAjax();
    ajax.open("POST", AJAX_URL, true);
    ajax.setRequestHeader("Content-type",
                        "application/x-www-form-urlencoded");
    ajax.send(jq);
}

function readAjax() {
    if(ajax.readyState == 4 && ajax.status == 200) {
        var msg = ajax.responseText;
        var errstr = "";
        try {
            errstr = "err decodeURI";
            msg = decodeURIComponent(msg);
            errstr = "err parse";
            var jsonrsp = JSON.parse(msg);
            errstr = "";
        }
        catch(err) {
            alert(errstr + " (msg:" + msg + ")");
            return;
        }

        if(ajaxActionFunc) {
            ajaxActionFunc(msg);
        }
    }
}

function eTextScroll(e)
{
    if(! e) e = window.event;
    var tgt = e.target ? e.target : e.srcElement;
    // console.debug("textscroll", tgt.id);
    switch(tgt.id) {
        case "tatext":
            divpreview.scrollTop  = tatext.scrollTop;
            divpreview.scrollLeft = tatext.scrollLeft;
            break;
    }
    return true;
}

// only happens when textarea loses focus
function eTextChange(e) {
    divpreview.innerHTML = tatext.value
        .replace(/<(\/?).>/g,  "&lt;$1i&gt;");
    pause_wordchecking();
    // clear_wordchecking();
}

function eTextLoad(e)
{
    if(! e) e = window.event;
    var tgt = e.target ? e.target : e.srcElement;
    // console.debug("textload", tgt.id);
}

function eTextReset(e)
{
    if(! e) e = window.event;
    var tgt = e.target ? e.target : e.srcElement;
    // console.debug("textreset", tgt.id);
}

function ePunc()
{
    // var punctest = 
    // /(\s(\.[^\.])|\s[:;,!\?]|[;!\?][^\s")]|(:[^\s\-])|\b\.\b)/;
    // divpreview.innerHTML
            // .replace(punctest, "<span class='puncerr'>$1</span>");
}

// rules
// from http://stackoverflow.com/questions/263743/how-to-get-cursor-position-in-textarea/3373056#3373056

function SelectionBounds() {
    var start = 0;
    var end = 0;
    var normalizedValue;
    var range;
    var textInputRange;
    var le;
    var endRange;
    var el = tatext;

    if(typeof el.selectionStart == "number" 
                && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end   = el.selectionEnd;
    } else {
        range = proofframe.document.selection.createRange();

        if(range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if start and end are at the very end
            // of input -- moveStart/moveEnd don't return 
            // what we want in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if(textInputRange.compareEndPoints(
                            "StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start)
                                    .split("\n").length - 1;

                if(textInputRange.compareEndPoints(
                                "EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue
                            .slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}

function eSetSort(e) {
    if(!e) e = window.event;

    var tgt = e.target ? e.target : e.srcElement;
    var key = tgt.id;
    switch(key)
    {
        case "lktitle":
        case "lkauthor":
        case "lklang":
        case "lkprojid":
        case "lkgenre":
        case "lkpm":
        case "lkdiff":
        case "lkround":
            break;
        default:
            return;
    }
    var vsort = $("sort");
    var vdesc = $("desc");

    if( vsort.value === key ) 
    {
        vdesc.value = (vdesc.value == '0') ? '1' : '0' ;
    }
    else 
    {
        vsort.value = key ;
        vdesc.value = '0' ;
    }
    var sf = $('searchform');
    sf.submit();
}

/*
function _dom_trackActiveElement(evt) {
  if (evt && evt.target && evt.target.id) { 
    console.debug("focus to " + evt.target.id);
    proofframe.document.activeElement = 
        // evt.target == document ? null : evt.target;
        evt.target;
  }
}
 
function _dom_trackActiveElementLost(evt) { 
    if(proofframe.document.activeElement)
        console.debug("losing " + proofframe.document.activeElement.id);
  proofframe.document.activeElement = null; 
}
 
// if (proofframe.document.addEventListener) {
  // proofframe.document.addEventListener("focus",_dom_trackActiveElement,true);
  // proofframe.document.addEventListener("blur",_dom_trackActiveElementLost,true);
// }
*/

// project_words

/*
function eLangChange(e) {
    document.wcform.submit();
}

function eSetTextMovers(e) {
    if(!e) { e = window.event; }
    document.wcform.btnleft.disabled =
    document.wcform.btnright.disabled = 
        (document.wcform.suggested_words
            .value.length == 0);
}

function eWordsToGood() {
    var t = SelectedText(document.wcform.suggested_words);
    if(t.length > 0)
    {
        document.wcform.good_words.value += ('\\n' + t);
        DeleteSelection(document.wcform.suggested_words);
    }
}

function eWordsToBad() {
    var t = SelectedText(document.wcform.suggested_words);
    if(t.length > 0)
    {
        document.wcform.bad_words.value += ('\\n' + t);
        DeleteSelection(document.wcform.suggested_words);
    }
}
*/

